<template>
    <div :id="id" class="svg-box"></div>
</template>

<script>
import Chart from '../chart.js'
import * as d3 from 'd3'
import { defineComponent, nextTick } from 'vue'

export default defineComponent({
    props: ['data', 'modelValue'],
    emits: ['update:modelValue'],
    data() {
        return {
            id: 'ac-home-doughnut',
        }
    },
    mounted() {
        nextTick(() => {
            this.initMap(this.data)
        })
    },
    methods: {
        initMap(data) {
            const me = this
            /* ----------------------------配置参数------------------------  */
            const chart = new Chart()
            chart.setId(this.id)
            const box = d3.select('#' + this.id)
            const { offsetWidth, offsetHeight } = box.node()
            const config = {
                margins: { top: 0, left: 0, bottom: 0, right: 0 },
                textColor: '#296FFF',
                textColorBlack: '#ffffff',
                hoverColor: '#296FFF',
                doughnutColor: '#296FFF',
                title: '闭环管控',
                innerRadius: 70,
                outerRadius: 110,
                textOffsetH: 0,
                lineColor: 'black',
                animateDuration: 1000,
            }

            chart.box(box)
            chart.margins(config.margins)

            chart.setId(this.id)
            chart.width(offsetWidth)
            chart.height(offsetHeight)

            /* ----------------------------尺度转换------------------------  */
            chart.arcAngle = d3
                .pie()
                .startAngle(-Math.PI / 3)
                .padAngle(0.05)
                .sort((d, i) => i)
                .value(d => d.value)

            /* ----------------------------渲染扇形------------------------  */
            chart.renderSlices = function () {
                const slices = chart
                    .body()
                    .append('g')
                    .classed('pie', true)
                    .attr('transform', 'translate(' + chart.getBodyWidth() / 2 + ',' + chart.getBodyHeight() / 2 + ')')
                    .selectAll('.arc')
                    .data(chart.arcAngle(data))

                slices
                    .enter()
                    .append('path')
                    .attr('class', (d, i) => 'arc arc-' + i)
                    .merge(slices)
                    .attr('stroke', 'none')
                    .attr('fill', config.doughnutColor)
                    .attr('opacity', d => {
                        if (d.data.status) {
                            return 0.5
                        }
                        return 0.2
                    })
                    .attr('cursor', d => {
                        if (d.data.status) {
                            return 'pointer'
                        }
                        return 'not-allowed'
                    })
                    .transition()
                    .duration(config.animateDuration)
                    .attrTween('d', arcTween)

                slices.exit().remove()

                const arc = d3.arc().outerRadius(config.outerRadius).innerRadius(config.innerRadius)

                function arcTween(d) {
                    let currentArc = this._current
                    if (!currentArc) {
                        currentArc = { startAngle: -Math.PI / 3, endAngle: -Math.PI / 3 }
                    }
                    const interpolate = d3.interpolate(currentArc, d)
                    this._current = interpolate(1) // 当饼图更新时，从当前角度过渡到新角度

                    return function (t) {
                        return arc(interpolate(t))
                    }
                }
            }

            /* ----------------------------渲染文本标签和线条------------------------  */
            chart.renderText = function () {
                // ----渲染文本标签-------
                const arc = d3.arc().outerRadius(config.outerRadius).innerRadius(config.innerRadius)
                const labels = d3
                    .select('.pie')
                    .append('g')
                    .attr('class', 'label-group')
                    .selectAll('.label')
                    .data(chart.arcAngle(data))

                const labelBox = labels.enter().append('g').classed('label', true).classed('pointer', true)
                // 类别
                labelBox
                    .append('text')
                    .merge(labels)
                    .attr('style', 'font-size:12px')
                    .attr('stroke', 'none')
                    .attr('fill', config.textColorBlack)
                    .attr('text-anchor', d => {
                        return (d.endAngle + d.startAngle) / 2 > Math.PI ? 'end' : 'start'
                    })
                    .attr('dy', (d, i) => {
                        let dy = 10
                        switch (i) {
                            case 0:
                            case 1:
                                dy = 8
                                break
                            case 3:
                            case 4:
                                dy = 5
                                break
                            default:
                                dy = 10
                                break
                        }
                        return dy
                    })
                    .attr('dx', (d, i) => {
                        let dx = 0
                        switch (i) {
                            case 2:
                                dx = -12
                                break
                            case 1:
                                dx = -8
                                break
                            case 0:
                                dx = -15
                                break
                            case 3:
                                dx = -12
                                break
                            case 4:
                                dx = 30
                                break
                            case 5:
                                dx = 12
                                break
                            default:
                                dx = 10
                                break
                        }
                        return dx
                    })
                    .transition()
                    .duration(0)
                    .delay(config.animateDuration)
                    .attr('transform', d => {
                        return 'translate(' + arc.centroid(d) + ')'
                    })
                    .text(d => d.data.type)

                labels.exit().remove()
            }

            /* ----------------------------渲染图标题------------------------  */
            chart.renderTitle = function () {
                chart
                    .svg()
                    .append('text')
                    .classed('title', true)
                    .attr('x', chart.width() / 2)
                    .attr('y', chart.height() / 2)
                    .attr('dy', 6)
                    .text(config.title)
                    .attr('style', 'font-size:10px')
                    .attr('fill', config.textColorBlack)
                    .attr('text-anchor', 'middle')
                    .attr('stroke', 'none')
            }

            /* ----------------------------绑定鼠标交互事件------------------------  */
            chart.addMouseOn = function () {
                const arcLarger = d3
                    .arc()
                    .outerRadius(config.outerRadius * 1.02)
                    .innerRadius(config.innerRadius * 0.98)

                const arcNormal = d3.arc().outerRadius(config.outerRadius).innerRadius(config.innerRadius)

                setTimeout(() => {
                    d3.select(`.arc-${me.modelValue}`)
                        .attr('d', d => arcLarger(d))
                        .transition()
                        .duration(config.animateDuration / 2)
                        .attr('opacity', 1)
                }, 1000)

                d3.selectAll('.arc')
                    .on('mouseover', function (d, i) {
                        if (d.data.status) {
                            d3.select(`.arc-${i}`)
                                .attr('d', arcLarger(d))
                                .transition()
                                .duration(config.animateDuration / 2)
                                .attr('opacity', 1)
                        }
                    })
                    .on('mouseleave', function (d, i) {
                        if (d.data.status && i !== me.modelValue) {
                            d3.select(`.arc-${i}`)
                                .attr('d', arcNormal(d))
                                .transition()
                                .duration(config.animateDuration / 2)
                                .attr('opacity', 0.5)
                        }
                    })
                    .on('click', function (d, i) {
                        if (d.data.status && i !== me.modelValue) {
                            d3.select(`.arc-${me.modelValue}`)
                                .attr('d', childD => arcNormal(childD))
                                .transition()
                                .duration(config.animateDuration / 2)
                                .attr('opacity', 0.5)
                            setTimeout(() => {
                                me.$emit('update:modelValue', i)
                            }, 100)
                        }
                    })
                d3.selectAll('.label')
                    .on('click', function (d, i) {
                        if (d.data.status && i !== me.modelValue) {
                            d3.select(`.arc-${me.modelValue}`)
                                .attr('d', childD => arcNormal(childD))
                                .transition()
                                .duration(config.animateDuration / 2)
                                .attr('opacity', 0.5)
                            setTimeout(() => {
                                me.$emit('update:modelValue', i)
                            }, 100)
                        }
                    })
                    .on('mouseover', function (d, i) {
                        if (d.data.status) {
                            d3.select(`.arc-${i}`)
                                .attr('d', arcLarger(d))
                                .transition()
                                .duration(config.animateDuration / 2)
                                .attr('opacity', 1)
                        }
                    })
            }

            chart.render = function () {
                chart.renderTitle()

                chart.renderSlices()

                chart.renderText()

                chart.addMouseOn()
            }

            chart.renderChart()
        },
    },
})
</script>

<style lang="scss" scoped>
.svg-box {
    height: 246px;
    width: 246px;
}
</style>
